define(['underscore', "tween", "three", "OrbitControls", "GLTFLoader"], (_, TWEEN, THREE) ->
  class Scene
    constructor: (dom) -> (
      @height = dom.clientHeight
      @width = dom.clientWidth
      
      @initCamera()
      @initScene()
      @initLight()
      @initRender()
      
      dom.appendChild(@renderer.domElement)

      @loadModel()
      
      @render()
    )

    initCamera: () -> (
      @camera = new THREE.PerspectiveCamera(45, @width / @height, 1, 5000);
      @camera.position.set(0, 200, -500);

      window.cameraHelp = @camera
      @target = {
        x: @camera.position.x - 100,
        y: @camera.position.y - 100,
        z: @camera.position.z - 100
      }

      @controls = new THREE.OrbitControls(@camera);
      @controls.rotateSpeed = 1.0;
      @controls.zoomSpeed = 1.2;
      @controls.panSpeed = 0.8;
    )

    initScene: () -> (
      @scene = new THREE.Scene()
    )

    initLight: () -> (
      color = new THREE.Color("white")
      @light = new THREE.AmbientLight( color )
      @scene.add(@light)
      @pointLight = new THREE.PointLight( color, 1, 100 )
      @scene.add(@pointLight)
    )

    initRender: () -> (
      @renderer = new THREE.WebGLRenderer({ antialias: true })
      @renderer.setSize(@width, @height);
    )

    loadModel: () -> (
      @materials = []
      @material1 = undefined
      @material2 = undefined
      gltfLoader = new THREE.GLTFLoader()
      gltfLoader.load("static/dark/scene.gltf", (gltf) => (
        grounds = new THREE.Group()
        gltf.scene.traverse((obj) =>
          return if !obj.isMesh
          clone = obj.clone()
          if obj.parent.name == "RootNode"
            clone.position.copy(obj.position)
            clone.rotation.copy(obj.rotation)
          else if obj.parent.parent.name == "RootNode"
            clone.position.copy(obj.parent.position)
            clone.rotation.copy(obj.parent.rotation)
          else if obj.parent.parent.name == "RootNode"
            clone.position.copy(obj.parent.position)
            clone.rotation.copy(obj.parent.rotation)
          else if obj.parent.parent.parent.name == "RootNode"
            clone.position.copy(obj.parent.parent.position)
            clone.rotation.copy(obj.parent.parent.rotation)
          if clone.material.name == "m_959139_01_alpha" || clone.material.name == "m_436512_01_重复50_alpha"
            clone.material.needsUpdate = true
            clone.material.map.needsUpdate = true
            @materials.push(clone.material)
          else if clone.material.name == "Material__178_alpha"
            clone.material.needsUpdate = true
            clone.material.map.needsUpdate = true
            @material1 = clone.material
            console.log(@material1)
          else if clone.material.name == "Material__179_alpha"
            clone.material.needsUpdate = true
            clone.material.map.needsUpdate = true
            @material2 = clone.material
          @scene.add(clone)
        )
      ))
    )

    render: () -> (
      TWEEN.update();
      @pointLight.position.copy(@camera.position)
      if @materials
        _.each(@materials, (material) =>
          material.map.offset.y -= 0.005
          if material.map.offset.y <= -0.5
            material.map.offset.y = 0
        )
      if @material1
        @material1.map.rotation += Math.PI / 1200
        if @material1.map.rotation >= Math.PI / 4
          @material1.map.rotation = 0
      if @material2
        @material2.map.rotation += Math.PI / 1200
        if @material2.map.rotation >= Math.PI / 4
          @material2.map.rotation = 0
      window.requestAnimationFrame(@render.bind(@))
      @renderer.render(@scene, @camera);
      @controls.update()
    )

    changeCamera: (index) -> (
      from = {
        x: @camera.position.x,
        y: @camera.position.y,
        z: @camera.position.z
      }

      to = @list[index]
      
      @tween = new TWEEN.Tween(from)
        .to(to, 600)
        .easing(TWEEN.Easing.Linear.None)
        .onUpdate(() =>
          @camera.position.set(from.x, from.y, from.z);
          @camera.lookAt(new THREE.Vector3(0, 0, 0));
        )
        .onComplete(() => 
          @controls.target.copy(@scene.position)
          if index <= @list.length - 2
            window.setTimeout(() =>
              @changeCamera(index + 1)
            , 1000)
        )
        .start();
    )

    changeBtn: () => (
      if @tween
        @tween.stop()
        TWEEN.remove(@tween)
      @list = [
        @target, 
        { x: 382, y: 221, z: -307 },
        { x: 2, y: -578, z: -212 },
        { x: -371, y: 221, z: -320 },
        { x: 0, y: 601, z: -136 },
        @target
      ]
      @changeCamera(0)
    )

  return Scene
)